package com.sun.async.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.sun.async.entity.ImportTask;
import com.sun.async.enums.ImportTaskStatusEnum;
import com.sun.async.service.AsyncExcelImportService;
import com.sun.async.service.FileStorageService;
import com.sun.async.service.ImportTaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Date;
import java.util.List;

/**
 * 异步Excel导入服务实现类
 */
@Slf4j
@Service
public class AsyncExcelImportServiceImpl implements AsyncExcelImportService {
    private static final Logger LOGGER = LoggerFactory.getLogger(AsyncExcelImportServiceImpl.class);

    @Autowired
    private ImportTaskService importTaskService;

    @Autowired
    private FileStorageService fileStorageService;

    @Async("asyncExecutor")
    @Override
    public <T> void asyncImportExcel(Long taskId, File file, ImportService<T> importService) {
        // 更新任务状态为处理中
        ImportTask task = importTaskService.getById(taskId);
        if (task == null) {
            LOGGER.error("任务不存在，taskId: {}", taskId);
            return;
        }

        task.setStatus(ImportTaskStatusEnum.PROCESSING.getCode());
        task.setStartTime(new Date());
        importTaskService.updateById(task);

        try {
            // 读取Excel数据
            List<T> dataList = readExcel(file, importService.getDtoClass());

            // 更新总行数
            task.setTotalRows(dataList.size());
            importTaskService.updateById(task);

            // 处理数据
            ImportResult result = importService.processData(dataList);

            // 更新任务状态
            updateTaskStatus(task, result);
        } catch (Exception e) {
            LOGGER.error("导入Excel失败，taskId: {}", taskId, e);
            task.setStatus(ImportTaskStatusEnum.FAILURE.getCode());
            task.setEndTime(new Date());
            importTaskService.updateById(task);
        }
    }

    /**
     * 读取Excel文件
     * @param file 文件
     * @param clazz DTO类
     * @param <T> DTO类型
     * @return 数据列表
     */
    private <T> List<T> readExcel(File file, Class<T> clazz) throws IOException {
        return EasyExcel.read(Files.newInputStream(file.toPath()))
                .head(clazz)
                .sheet()
                .doReadSync();
    }

    /**
     * 更新任务状态
     * @param task 任务
     * @param result 导入结果
     */
    private void updateTaskStatus(ImportTask task, ImportResult result) {
        task.setSuccessRows(result.getSuccessCount());
        task.setFailRows(result.getFailedRecords() != null ? result.getFailedRecords().size() : 0);
        task.setErrorFilePath(result.getErrorFilePath());

        if (result.getFailedRecords() == null || result.getFailedRecords().isEmpty()) {
            task.setStatus(ImportTaskStatusEnum.SUCCESS.getCode());
        } else if (result.getSuccessCount() == 0) {
            task.setStatus(ImportTaskStatusEnum.FAILURE.getCode());
        } else {
            task.setStatus(ImportTaskStatusEnum.PARTIAL_SUCCESS.getCode());
        }

        task.setEndTime(new Date());
        importTaskService.updateById(task);
    }

    /**
     * 生成错误文件
     * @param originalFileName 原文件名
     * @param failedRecords 失败记录
     * @param <T> DTO类型
     * @return 错误文件路径
     */
    private <T> String generateErrorFile(String originalFileName, List<T> failedRecords) {
        if (CollectionUtils.isEmpty(failedRecords)) {
            return null;
        }

        try {
            // 创建临时文件
            String fileName = System.currentTimeMillis() + "_error_" + originalFileName;
            File errorFile = new File(fileStorageService.getUploadPath(), fileName);

            // 设置表头样式
            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            headWriteCellStyle.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex());
            WriteFont headWriteFont = new WriteFont();
            headWriteFont.setFontHeightInPoints((short)12);
            headWriteFont.setBold(true);
            headWriteCellStyle.setWriteFont(headWriteFont);

            // 设置内容样式
            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
            contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
            contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
            contentWriteCellStyle.setBorderTop(BorderStyle.THIN);

            // 水平样式策略
            HorizontalCellStyleStrategy horizontalCellStyleStrategy =
                    new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

            // 获取DTO类
            Class<?> dtoClass = failedRecords.get(0).getClass();

            // 写入错误文件
            EasyExcel.write(errorFile, dtoClass)
                    .registerWriteHandler(horizontalCellStyleStrategy)
                    .sheet("错误数据")
                    .doWrite(failedRecords);

            return fileStorageService.getRelativePath(fileName);
        } catch (Exception e) {
            LOGGER.error("生成错误文件失败", e);
            return null;
        }
    }
}